package com.homwee.serialportinspection.tv;

import static com.homwee.serialportinspection.util.Util.resetini;

import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ComponentName;
import android.content.pm.PackageManager;
import android.media.AudioManager;
import android.net.ConnectivityManager;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.provider.Settings;
//import android.support.v4.app.ActivityCompat;
import androidx.core.app.ActivityCompat;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;

import com.homwee.serialportinspection.SerialPortInspectionActivity;
import com.homwee.serialportinspection.model.Types;
import com.homwee.serialportinspection.util.Contants;
import com.homwee.serialportinspection.util.Util;
import com.mediatek.twoworlds.factory.MtkTvFApiDisplay;
import com.mediatek.twoworlds.factory.MtkTvFApiDisplayTest;
import com.mediatek.twoworlds.factory.MtkTvFApiInformation;
import com.mediatek.twoworlds.factory.MtkTvFApiSystem;
import com.mediatek.twoworlds.factory.common.MtkTvFApiDisplayTypes;
import com.mediatek.twoworlds.factory.common.MtkTvFApiKeyManager;
import com.mediatek.twoworlds.factory.common.MtkTvFApiSystemTypes;
import com.mediatek.twoworlds.factory.model.MtkTvFApiDispTstPattern;
import com.mediatek.twoworlds.factory.model.MtkTvFApiSysFactorySvcCmd_e;
import com.mediatek.twoworlds.tv.MtkTvBroadcast;
import com.mediatek.twoworlds.tv.MtkTvChannelList;
import com.mediatek.twoworlds.tv.MtkTvConfig;
import com.mediatek.twoworlds.tv.MtkTvInputSource;
import com.mediatek.twoworlds.tv.SystemProperties;
import com.mediatek.twoworlds.tv.common.MtkTvChCommonBase;
import com.mediatek.twoworlds.tv.common.MtkTvConfigType;
import com.mediatek.twoworlds.tv.model.MtkTvChannelInfoBase;

import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Set;



public class Antv implements Tv {
    private static final String TAG = "Antv";

    private static final int START_BT_CHECK_MS = 5000;  // 5s

    private static final int SPDIF_DOLBY_DIGITAL = 1;
    private static final int SPDIF_PCM = 2;
    private static final int SPDIF_BYPASS = 4;
    private static final int SPDIF_DOLBY_DIGITAL_PLUS = 5;
    private static final int SPDIF_AUTO = 7;
    private static final int SPDIF_DEFAULT = SPDIF_AUTO;

    private static final int PICTURE_MODE_USER = 0;
    private static final int PICTURE_MODE_STANDARD = 7;
    private static final int PICTURE_MODE_VIVID = 3;
    private static final int PICTURE_MODE_SPORT = 2;
    private static final int PICTURE_MODE_MOVIE = 9;
    private static final int PICTURE_MODE_GAME = 10;
    private static final int PICTURE_MODE_ENERGY_SAVING = 11;
    private static final int PICTURE_MODE_DEFAULT = PICTURE_MODE_STANDARD;

    private static final int COLOR_TEMPERATURE_USER = 0;
    private static final int COLOR_TEMPERATURE_COOL = 1;
    private static final int COLOR_TEMPERATURE_STANDARD = 2;
    private static final int COLOR_TEMPERATURE_WARM = 3;
    private static final int COLOR_TEMPERATURE_DEFAULT = COLOR_TEMPERATURE_STANDARD;

    private static final int SOUND_MODE_STANDARD = 1;
    private static final int SOUND_MODE_VIVID = 2;
    private static final int SOUND_MODE_SPORT = 3;
    private static final int SOUND_MODE_MOVIE = 4;
    private static final int SOUND_MODE_MUSIC = 5;
    private static final int SOUND_MODE_NEWS = 6;
    private static final int SOUND_MODE_USER = 7;

    private static final int BALANCE_LEFT = -50;
    private static final int BALANCE_RIGHT = 50;
    private static final int BALANCE_STEREO = 0;

    private static final String SETTINGS_SECURE_SLEEP_TIMEOUT = "sleep_timeout";

    private static final int MTK_ANTENNA_AIR = 1;
    private static final int MTK_ANTENNA_CABLE = 2;
    private static final int MTK_ANTENNA_SATELLITE = 3;

    private static final int BYTE_MASK = 0xff;
    private static final int SHORT_BITS = 16;
    private static final int BYTE_BITS = 8;

    private static final int SECONDS_IN_ONE_MINUTE = 60;
    private static final int MS_IN_ONE_SECONDS = 1000;

    private static final int MINUTE_ZERO = 0;
    private static final int MINUTE_FIVE = 5;
    private static final int MINUTE_TEN = 10;
    private static final int MINUTE_FIFTEEN = 15;
    private static final int MINUTE_THIRTY = 30;
    private static final int MINUTE_SIXTY = 60;

    /**
     * File path
     */
    private static final String KEY_PATH_HDCP2 = "/vendor/tvcertificate/hdcp2_key.bin";
    private static final String PATH_PROJECT_INI = "/vendor/tvcertificate/project_id.ini";
    private static final String FACTORY_PROJECT_ID= "product:project_id";
    private static final String FACTORY_PAGE1_AQ_VERSION_PATH = "/vendor/tvconfig/config/aq/AQ_Version.ini";
    private static final String FACTORY_INI_PANEL_VER = "INIVERSION:VER";
    private static final String FACTORY_PAGE2_CUSTOMER_PATH = "/vendor/config/model/Customer_1.ini";

    /**
     * Key Status
     */
    private static final String KEYSTATUS_FILEPATH = "/vendor/tvcertificate/keystatus.ini";
    private static final String KEYSTATUS_HDCP14 = "FACTORY_CONFIG:HDCPKEY14";
    private static final String KEYSTATUS_HDCP2 = "FACTORY_CONFIG:HDCPKEY2";
    private static final String KEYSTATUS_WIDEVINE = "FACTORY_CONFIG:WIDEVINE";
    private static final String KEYSTATUS_KEYMASTER = "FACTORY_CONFIG:KEYMASTER";
    private static final String KEYSTATUS_PLAYREADY = "FACTORY_CONFIG:PLAYREADY";
    private static final String KEYSTATUS_PLAYREADY25 = "FACTORY_CONFIG:TEMP1";

    /**
     * Init para
     */
    public static final String FACTORY_INI_PANEL_PATH = "panel:m_pPanelName";

    /**
     * Constants
     */
    public static final String PROPERTIE_BUILDTIME = "ro.vendor.build.date";

    /**
     * btReceiver register flag
     * false : unregister
     * true : registered
     */
    private boolean btReceiverFlag = false;

    /**
     * Wireless receiver
     */
    private BroadcastReceiver wifiReceiver = null;
    private IntentFilter wifiIntentFilter = null;

    /**
     * wifiReceiverFlag register flag
     * false : unregister
     * true : registered
     */
    private boolean wifiReceiverFlag = false;

    private Types.ColorTempMode[] mFactoryCtModeMap = {// indexed by MtkTvFApiDisplayTypes.EnumColorTemperature
        Types.ColorTempMode.USER, Types.ColorTempMode.COOL, Types.ColorTempMode.STANDARD, Types.ColorTempMode.WARM
    };

    private int[] mNoSignalPowerOffTimeMap = {// indexed by MtkNoSignalPowerOffMode
        MINUTE_ZERO, MINUTE_FIVE, MINUTE_TEN, MINUTE_FIFTEEN, MINUTE_THIRTY, MINUTE_SIXTY
    };

    private Context mContext;
    private List<ResultListener> mListeners = new ArrayList<>();

    private WifiManager mWifiManager;
    private List<MtkTvChannelInfoBase> mChannels;
    private List<ScanResult> mWifiScanResult = new ArrayList<>();
    private BluetoothDevice mBtDiscoveryDev = null;
    private String mBtAp = null;
    private long mStartBtDiscoveryTime = System.currentTimeMillis();

    public Antv(Context context) {
        mContext = context;
        mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
        mChannels = getChannelList();

        if (false == wifiReceiverFlag) {
            wifiReceiver = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    mWifiScanResult = mWifiManager.getScanResults();
                    for (ResultListener l : mListeners) {
                        l.onWifiScanResult(mWifiScanResult);
                    }
                }
            };
            wifiIntentFilter = new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
            mContext.registerReceiver(wifiReceiver, wifiIntentFilter);
            wifiReceiverFlag = true;
        }

        // need call MtkTvMultiView.startMainVideo(currSrcId, new Region_Info_T(0, 0, 10000, 10000)) to start if disable livetv
    }

    @Override
    public void UninitAntv() {
        unRegisterWifiReceiver();
        unregisterBtReceiver();
    }

    @Override
    public boolean powerOff() {
        try {
            Runtime runtime = Runtime.getRuntime();
            runtime.exec("input keyevent --longpress  " + KeyEvent.KEYCODE_POWER);
        } catch (IOException e) {
            Log.e(TAG, "Exception when send long keyCode");
            return false;
        }
        return true;
    }

    @Override
    public boolean standby() {
        try {
            Runtime runtime = Runtime.getRuntime();
            runtime.exec("input keyevent " + KeyEvent.KEYCODE_POWER);
        } catch (IOException e) {
            Log.e(TAG, "Exception when send keyCode");
            return false;
        }
        return true;
    }

    @Override
    public boolean setInputSource(Types.InputSource inputSource) {
        boolean result = false;
        int id = toMtkSourceId(inputSource);
        if (id != Types.INVALID) {
            hideUI();
            //result = MtkTvInputSource.getInstance().changeInputSourcebySourceid(id) == 0;
        switch (inputSource) {
            case ATV:
				sendKeyEvent(KeyEvent.KEYCODE_SWITCH_CHARSET);
                break;
            case DTV:
				sendKeyEvent(KeyEvent.KEYCODE_CAMERA);
                break;

            case CVBS:
				sendKeyEvent(KeyEvent.KEYCODE_DVR);
                break;

            case HDMI:
				sendKeyEvent(KeyEvent.KEYCODE_TV_INPUT_HDMI_1);
				break;
            case HDMI2:
				sendKeyEvent(KeyEvent.KEYCODE_TV_INPUT_HDMI_2);
				break;
            case HDMI3:
				sendKeyEvent(KeyEvent.KEYCODE_TV_INPUT_HDMI_3);
				break;
            case HDMI4:
				sendKeyEvent(KeyEvent.KEYCODE_TV_INPUT_HDMI_4);
				break;
        }
		}

        return result;
    }

    @Override
    public int getInputSource() {
        int source = Types.INVALID;
        String curr = MtkTvInputSource.getInstance().getCurrentInputSourceName();
        for (MtkSourceId id : MtkSourceId.values()) {
            String name = MtkTvInputSource.getInstance().getInputSourceNamebySourceid(id.ordinal());
            if (name.equals(curr)) {
                source = fromMtkSourceId(id);
                break;
            }
        }

        return source;
    }

    @Override
    public boolean playChannel(Types.ChannelType channelType, int channelNum) {
        boolean result = false;
        MtkTvChannelInfoBase channel = findChannel(channelType, channelNum, mChannels);
        if (channel == null) {
            Log.e("TAG", "can't find channel type = " + channelType + ", num = " + channelNum);
        } else {
            int value = MtkTvBroadcast.getInstance().channelSelect(channel, false);
            if (value == 0) {
                result = MtkTvChannelList.setCurrentChannel(channel) == 0;
            } else {
                Log.e(TAG, "channel select fail result = " + value);
            }
        }

        return result;
    }

    @Override
    public boolean getCurrChannel(int[] channel) {
        boolean result = true;

        MtkTvChannelInfoBase c = MtkTvChannelList.getCurrentChannel();
        if (c == null) {
            Log.e(TAG, "not exist current channel");
            result = false;
        } else {
            channel[0] = toChannelType(c.getBrdcstMedium());
            channel[1] = c.getChannelNumber();
        }

        return result;
    }

    @Override
    public boolean setVolume(int volume) {
        AudioManager mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
        mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_SHOW_UI);
        return true;
    }

    @Override
    public int getVolume() {
        AudioManager mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
        return mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);

    }

    @Override
    public boolean setSpdifMode(Types.SpdifMode mode) {
        switch (mode) {
            case AUTO:
                Settings.Global.putInt(mContext.getContentResolver(), "sound_spdif_type", SPDIF_AUTO);
                break;
            case BYPASS:
                Settings.Global.putInt(mContext.getContentResolver(), "sound_spdif_type", SPDIF_BYPASS);
                break;
            case PCM:
                Settings.Global.putInt(mContext.getContentResolver(), "sound_spdif_type", SPDIF_PCM);
                break;
            case DOLBY_DIGITAL_PLUS:
                Settings.Global.putInt(mContext.getContentResolver(), "sound_spdif_type", SPDIF_DOLBY_DIGITAL_PLUS);
                break;
            case DOLBY_DIGITAL:
                Settings.Global.putInt(mContext.getContentResolver(), "sound_spdif_type", SPDIF_DOLBY_DIGITAL);
                break;
            default:
                return false;
        }
        return true;
    }

    @Override
    public int getSpdifMode() {
        int spdifMode = Settings.Global.getInt(
                mContext.getContentResolver(), "sound_spdif_type", SPDIF_DEFAULT);
        int mode;
        switch (spdifMode) {
            case SPDIF_AUTO:
                mode = Types.SpdifMode.AUTO.ordinal();
                break;
            case SPDIF_BYPASS:
                mode = Types.SpdifMode.BYPASS.ordinal();
                break;
            case SPDIF_PCM:
                mode = Types.SpdifMode.PCM.ordinal();
                break;
            case SPDIF_DOLBY_DIGITAL_PLUS:
                mode = Types.SpdifMode.DOLBY_DIGITAL_PLUS.ordinal();
                break;
            case SPDIF_DOLBY_DIGITAL:
                mode = Types.SpdifMode.DOLBY_DIGITAL.ordinal();
                break;
            default:
                mode = Types.INVALID;
        }
        return mode;
    }

    @Override
    public boolean setPictureMode(Types.PictureMode mode) {
        switch (mode) {
            case STANDARD:
                Settings.Global.putInt(mContext.getContentResolver(), "picture_mode", PICTURE_MODE_STANDARD);
                break;
            case VIVID:
                Settings.Global.putInt(mContext.getContentResolver(), "picture_mode", PICTURE_MODE_VIVID);
                break;
            case SPORT:
                Settings.Global.putInt(mContext.getContentResolver(), "picture_mode", PICTURE_MODE_SPORT);
                break;
            case MOVIE:
                Settings.Global.putInt(mContext.getContentResolver(), "picture_mode", PICTURE_MODE_MOVIE);
                break;
            case GAME:
                Settings.Global.putInt(mContext.getContentResolver(), "picture_mode", PICTURE_MODE_GAME);
                break;
            case ENERGY_SAVING:
                Settings.Global.putInt(mContext.getContentResolver(), "picture_mode", PICTURE_MODE_ENERGY_SAVING);
                break;
            case USER:
                Settings.Global.putInt(mContext.getContentResolver(), "picture_mode", PICTURE_MODE_USER);
                break;
            default:
                return false;
        }
        return true;
    }

    @Override
    public int getPictureMode() {
        int pictureMode = Settings.Global.getInt(
                mContext.getContentResolver(), "picture_mode", PICTURE_MODE_DEFAULT);
        int mode;
        switch (pictureMode) {
            case PICTURE_MODE_STANDARD:
                mode = Types.PictureMode.STANDARD.ordinal();
                break;
            case PICTURE_MODE_VIVID:
                mode = Types.PictureMode.VIVID.ordinal();
                break;
            case PICTURE_MODE_SPORT:
                mode = Types.PictureMode.SPORT.ordinal();
                break;
            case PICTURE_MODE_MOVIE:
                mode = Types.PictureMode.MOVIE.ordinal();
                break;
            case PICTURE_MODE_GAME:
                mode = Types.PictureMode.GAME.ordinal();
                break;
            case PICTURE_MODE_ENERGY_SAVING:
                mode = Types.PictureMode.ENERGY_SAVING.ordinal();
                break;
            case PICTURE_MODE_USER:
                mode = Types.PictureMode.USER.ordinal();
                break;
            default:
                mode = Types.INVALID;
                break;
        }

        return mode;
    }

    @Override
    public boolean setMModeEnable(boolean isEnable) {
        boolean success = false;
        int mode = isEnable ? 1 : 0;

        success = (MtkTvFApiInformation.getInstance().setIniParameter(
                Contants.PATH_FACTORYINI, Contants.FACTORY_M_MODE, "" + mode) == -1) ? false : true;

        if (mode == 0) {
            MtkTvFApiSystem.getInstance().setFactoryPowerMode(
                    MtkTvFApiSystemTypes
                            .EnumSystemFactoryPowerMode
                            .E_MTK_FAPI_SYSTEM_FACTORY_POWER_MODE_SECONDARY);
        } else {
            MtkTvFApiSystem.getInstance().setFactoryPowerMode(
                    MtkTvFApiSystemTypes
                            .EnumSystemFactoryPowerMode
                            .E_MTK_FAPI_SYSTEM_FACTORY_POWER_MODE_DIRECT);

        }

        Settings.System.putInt(
                mContext.getContentResolver(), Contants.FACTORY_M_MODE_GO, mode);
        return success;
    }

    @Override
    public boolean isMMode() {
        boolean factoryMode = false;
        String strFactoryMode = null;

        strFactoryMode = MtkTvFApiInformation
                .getInstance()
                .getIniParameter(Contants.PATH_FACTORYINI, Contants.FACTORY_M_MODE);

        if (strFactoryMode != null) {
            factoryMode = strFactoryMode.equalsIgnoreCase("1") ? true : false;
        }
        return factoryMode;
    }

    @Override
    public boolean enterFactoryMenu() {
        return sendKeyEvent(KeyEvent.KEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP);
    }

    @Override
    public boolean exitFactoryMenu() {
        return sendKeyEvent(KeyEvent.KEYCODE_MENU);
    }

    @Override
    public boolean factoryReset() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                MtkTvFApiDisplayTest mMtkTvFApiDisplayTest = MtkTvFApiDisplayTest.getInstance();
                mMtkTvFApiDisplayTest.setBurningMode(false);
                MtkTvFApiSystem mMtkTvFApiSystem = MtkTvFApiSystem.getInstance();
                mMtkTvFApiSystem.setUartEnvironment(false);
                mMtkTvFApiSystem.setFactoryPowerMode(MtkTvFApiSystemTypes.EnumSystemFactoryPowerMode.E_MTK_FAPI_SYSTEM_FACTORY_POWER_MODE_SECONDARY);
                resetini();
                Intent resetIntent = new Intent("android.intent.action.FACTORY_RESET");
                resetIntent.setPackage("android");
                resetIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
                resetIntent.putExtra("android.intent.extra.REASON", "ResetConfirmFragment");
                resetIntent.putExtra("shutdown", true);
                mContext.getApplicationContext().sendBroadcast(resetIntent);
            }
        }).start();

        return true;
    }

    @Override
    public boolean setBacklight(int backlight) {
        Settings.Global.putInt(mContext.getContentResolver(), "picture_backlight", backlight);
        return true;
    }

    @Override
    public int getBacklight() {
        int mBacklight = Settings.Global.getInt(mContext.getContentResolver(), "picture_backlight", 0);
        return mBacklight;
    }

    @Override
    public boolean setContrast(int contrast) {
        Settings.Global.putInt(mContext.getContentResolver(), "picture_contrast", contrast);
        return true;
    }

    @Override
    public int getContrast() {
        int mContrast = Settings.Global.getInt(mContext.getContentResolver(), "picture_contrast", 0);
        return mContrast;
    }

    @Override
    public String getSwVersion() {
        return Util.get("vendor.cus.product.fw.version");
    }

    @Override
    public boolean resetWB() {
        return false;
    }

    @Override
    public boolean setWB(Types.ColorPart part, int value) {
        switch (part) {
            case RED:
                Settings.Global.putInt(mContext.getContentResolver(), "picture_red_gain", value);
                break;
            case GREEN:
                Settings.Global.putInt(mContext.getContentResolver(), "picture_green_gain", value);
                break;
            case BLUE:
                Settings.Global.putInt(mContext.getContentResolver(), "picture_blue_gain", value);
                break;
            default:
                return false;
        }
        return true;
    }

    @Override
    public int getWB(Types.ColorPart part) {
        switch (part) {
            case RED:
                return Settings.Global.getInt(mContext.getContentResolver(), "picture_red_gain", 0);
            case GREEN:
                return Settings.Global.getInt(mContext.getContentResolver(), "picture_green_gain", 0);
            case BLUE:
                return Settings.Global.getInt(mContext.getContentResolver(), "picture_blue_gain", 0);
            default:
                return Types.INVALID;
        }
    }

    @Override
    public boolean setCtMode(Types.ColorTempMode mode) {
        switch (mode) {
            case STANDARD:
                Settings.Global.putInt(mContext.getContentResolver(), "picture_color_temperature", COLOR_TEMPERATURE_STANDARD);
                break;
            case COOL:
                Settings.Global.putInt(mContext.getContentResolver(), "picture_color_temperature", COLOR_TEMPERATURE_COOL);
                break;
            case WARM:
                Settings.Global.putInt(mContext.getContentResolver(), "picture_color_temperature", COLOR_TEMPERATURE_WARM);
                break;
            case USER:
                Settings.Global.putInt(mContext.getContentResolver(), "picture_color_temperature", COLOR_TEMPERATURE_USER);
                break;
            default:
                return false;
        }
        return true;
    }

    @Override
    public int getCtMode() {
        int colorTempMode = Settings.Global.getInt(
                mContext.getContentResolver(), "picture_color_temperature", COLOR_TEMPERATURE_DEFAULT);
        int mode;
        switch (colorTempMode) {
            case COLOR_TEMPERATURE_STANDARD:
                mode = Types.ColorTempMode.STANDARD.ordinal();
                break;
            case COLOR_TEMPERATURE_COOL:
                mode = Types.ColorTempMode.COOL.ordinal();
                break;
            case COLOR_TEMPERATURE_WARM:
                mode = Types.ColorTempMode.WARM.ordinal();
                break;
            case COLOR_TEMPERATURE_USER:
                mode = Types.ColorTempMode.USER.ordinal();
                break;
            default:
                mode = Types.INVALID;
                break;
        }

        return mode;
    }

    @Override
    public boolean showCtValue() {
        startInspectionActivity(mContext, "rgb");
        return true;
    }

    @Override
    public boolean hideCtValue() {
        boolean ret = false;
        if (SerialPortInspectionActivity.getInstance() != null) {
            SerialPortInspectionActivity.getInstance().finish();
            ret = true;
        }
        return ret;
    }

    @Override
    public boolean showPattern(int color) {
        if (false) {    // old solution, use Activity display pattern
            startInspectionActivity(mContext, null);
            Intent intent = new Intent(ACTION_SHOW);
            intent.putExtra("content", Tv.CONTENT_PATTERN);
            intent.putExtra("pattern", color);
            mContext.sendBroadcast(intent);
            return true;
        } else {    // use video generate pattern
            MtkTvFApiDispTstPattern pattern = new MtkTvFApiDispTstPattern();
            pattern.mIsModEnable = true;
            pattern.mModRData = color >> SHORT_BITS & BYTE_MASK;
            pattern.mModGData = color >> BYTE_BITS & BYTE_MASK;
            pattern.mModBData = color & BYTE_MASK;
            Log.d(TAG, "pattern r = " + pattern.mModRData + ", g = " + pattern.mModGData + ", b = " + pattern.mModBData);
            return MtkTvFApiDisplayTest.getInstance().generateTestPattern(MtkTvFApiDisplayTest.VIDEO_MUTE_COLOR_MODE, pattern) == 0;
        }
    }

    @Override
    public boolean closePattern() {
        MtkTvFApiDispTstPattern patternMode = new MtkTvFApiDispTstPattern();
        patternMode.mIsModEnable = false;
        patternMode.mModRData = 0;
        patternMode.mModGData = 0;
        patternMode.mModBData = 0;
        return MtkTvFApiDisplayTest.getInstance().generateTestPattern(MtkTvFApiDisplayTest.VIDEO_MUTE_COLOR_MODE, patternMode) == 0;
    }

    @Override
    public boolean factorySetWB(Types.InputSource source, Types.ColorTempMode mode, Types.FactoryColorTempData ctData) {
        int mtkSourceType = toMtkSourceType(source);
        int mtkCtMode = toMtkFactoryCtMode(mode);
        MtkTvFApiDisplayTypes.ColorTempData mtkCtData = toMtkCtData(ctData);
        if (mtkSourceType == Types.INVALID || mtkCtMode == Types.INVALID) {
            Log.e(TAG, "unknown mtk source type = " + mtkSourceType + " or CT mode = " + mtkCtMode);
            return false;
        }

        Log.d(
                TAG, "setWB mtkSourceType = " + MtkTvFApiDisplayTypes.EnumInputSourceType.values()[mtkSourceType]
                        + ", mtkCTMode = "
                        + MtkTvFApiDisplayTypes.EnumColorTemperature.values()[mtkCtMode]);
        return MtkTvFApiDisplay.getInstance().setWbGainOffsetEx(
                MtkTvFApiDisplayTypes.EnumColorTemperature.values()[mtkCtMode], mtkCtData, mtkSourceType) == 0;
    }

    @Override
    public boolean factorySetWB(Types.FactoryColorTempData ctData) {
        int source = getInputSource();
        int ctMode = getCtMode();
        if (source == Types.INVALID || ctMode == Types.INVALID) {
            Log.e(TAG, "error source = " + source + " or CT mode = " + ctMode);
            return false;
        }

        return factorySetWB(Types.InputSource.values()[source], Types.ColorTempMode.values()[ctMode], ctData);
    }

    @Override
    public boolean factorySetWB(int  ctMode ,Types.FactoryColorTempData ctData) {
        int source = getInputSource();

        return factorySetWB(Types.InputSource.values()[source], Types.ColorTempMode.values()[ctMode], ctData);
    }

    @Override
    public boolean factorySetWB(Types.ColorTempMode mode, Types.ColorPart part, int gain) {
        int source = getInputSource();

        boolean ret = false;
        if (source == Types.INVALID) {
            Log.e(TAG, "error get source = " + source);
            return false;
        }

        Types.FactoryColorTempData ctData = factoryGetWB(Types.InputSource.values()[source], mode);
        switch (part) {
            case RED:
                ctData.rGain = gain;
                break;

            case GREEN:
                ctData.gGain = gain;
                break;

            case BLUE:
                ctData.bGain = gain;
                break;

            default:
                Log.e(TAG, "unspport color part = " + part);
                return false;
        }

        for (MtkSourceId id : MtkSourceId.values()) {
            int chSource = fromMtkSourceId(id);
            if (chSource != Types.INVALID) {
                ret = factorySetWB(Types.InputSource.values()[chSource], mode, ctData);
            }
        }

        return ret;
    }

    @Override
    public Types.FactoryColorTempData factoryGetWB(Types.InputSource source, Types.ColorTempMode mode) {
        int mtkSourceType = toMtkSourceType(source);
        int mtkCtMode = toMtkFactoryCtMode(mode);
        if (mtkSourceType == Types.INVALID || mtkCtMode == Types.INVALID) {
            Log.e(TAG, "unknown mtk source type = " + mtkSourceType + " or CT mode = " + mtkCtMode);
            return null;
        }

        Log.d(
                TAG, "getWB mtkSourceType = "
                        + MtkTvFApiDisplayTypes.EnumInputSourceType.values()[mtkSourceType]
                        + ", mtkCTMode = "
                        + MtkTvFApiDisplayTypes.EnumColorTemperature.values()[mtkCtMode]);
        MtkTvFApiDisplayTypes.ColorTempData mtkCtData =
                MtkTvFApiDisplay.getInstance().getWbGainOffsetEx(
                        MtkTvFApiDisplayTypes.EnumColorTemperature.values()[mtkCtMode], mtkSourceType);
        if (mtkCtData == null) {
            Log.e(TAG, "get mtk factory CT data = " + mtkCtData);
            return null;
        }

        return fromMtkCtData(mtkCtData);
    }

    @Override
    public Types.FactoryColorTempData factoryGetWB() {
        int source = getInputSource();
        int ctMode = getCtMode();
        if (source == Types.INVALID || ctMode == Types.INVALID) {
            Log.e(TAG, "error source = " + source + " or CT mode = " + ctMode);
            return null;
        }

        return factoryGetWB(Types.InputSource.values()[source], Types.ColorTempMode.values()[ctMode]);
    }

    @Override
    public int factoryGetWB(Types.ColorTempMode mode, Types.ColorPart part) {
        int source = getInputSource();
        if (source == Types.INVALID) {
            Log.e(TAG, "error get source = " + source);
            return Types.INVALID;
        }

        int gain = Types.INVALID;
        Types.FactoryColorTempData ctData = factoryGetWB(Types.InputSource.values()[source], mode);
        switch (part) {
            case RED:
                gain = ctData.rGain;
                break;

            case GREEN:
                gain = ctData.gGain;
                break;

            case BLUE:
                gain = ctData.bGain;
                break;

            default:
                Log.e(TAG, "unspport color part = " + part);
                gain = Types.INVALID;
        }

        return gain;
    }

    @Override
    public boolean factoryWbPattern(int percent, boolean isEnable) {
        MtkTvFApiDispTstPattern pattern = new MtkTvFApiDispTstPattern();
        pattern.mIsIpMuxEnable = false;
        pattern.mIsIpEnable = 0;
        pattern.mMiuLineBuff = false;
        pattern.mLineBuffHvsp = false;
        pattern.mIsVopEnable = false;
        pattern.mIsVop2Enable = false;
        pattern.mIsModEnable = false;
        pattern.mIsWhiteBalanceEnable = isEnable;
        pattern.mWhiteFieldRatio = percent;

        return MtkTvFApiDisplayTest.getInstance().generateTestPattern(MtkTvFApiDisplayTest.XC_WHITE_BALANCE_PATTERN_MODE, pattern) == 0;
    }

    @Override
    public boolean hideUI() {
        Intent intent = new Intent(ACTION_SHOW);
        intent.putExtra("content", Tv.CONTENT_VIDEO);
        mContext.sendBroadcast(intent);

        return true;
    }

    @Override
    public boolean setSoundMode(Types.SoundMode mode) {
        switch (mode) {
            case STANDARD:
                Settings.Global.putInt(mContext.getContentResolver(), "sound_style", SOUND_MODE_STANDARD);
                break;
            case VIVID:
                Settings.Global.putInt(mContext.getContentResolver(), "sound_style", SOUND_MODE_VIVID);
                break;
            case SPORT:
                Settings.Global.putInt(mContext.getContentResolver(), "sound_style", SOUND_MODE_SPORT);
                break;
            case MOVIE:
                Settings.Global.putInt(mContext.getContentResolver(), "sound_style", SOUND_MODE_MOVIE);
                break;
            case MUSIC:
                Settings.Global.putInt(mContext.getContentResolver(), "sound_style", SOUND_MODE_MUSIC);
                break;
            case NEWS:
                Settings.Global.putInt(mContext.getContentResolver(), "sound_style", SOUND_MODE_NEWS);
                break;
            case USER:
                Settings.Global.putInt(mContext.getContentResolver(), "sound_style", SOUND_MODE_USER);
                break;
            default:
                return false;
        }
        return true;
    }

    @Override
    public int getSoundMode() {
        int soundMode = Settings.Global.getInt(
                mContext.getContentResolver(), "sound_style", 1);
        int mode;
        switch (soundMode) {
            case SOUND_MODE_STANDARD:
                mode = Types.SoundMode.STANDARD.ordinal();
                break;
            case SOUND_MODE_VIVID:
                mode = Types.SoundMode.VIVID.ordinal();
                break;
            case SOUND_MODE_SPORT:
                mode = Types.SoundMode.SPORT.ordinal();
                break;
            case SOUND_MODE_MOVIE:
                mode = Types.SoundMode.MOVIE.ordinal();
                break;
            case SOUND_MODE_MUSIC:
                mode = Types.SoundMode.MUSIC.ordinal();
                break;
            case SOUND_MODE_NEWS:
                mode = Types.SoundMode.NEWS.ordinal();
                break;
            case SOUND_MODE_USER:
                mode = Types.SoundMode.USER.ordinal();
                break;
            default:
                mode = Types.INVALID;
                break;
        }

        return mode;
    }

    @Override
    public boolean setMute(boolean isMute) {
        boolean cmdRet = true;
        if (isMute() && !isMute) { //unmute
            cmdRet = sendKeyEvent(KeyEvent.KEYCODE_VOLUME_MUTE);

        } else if (!isMute() && isMute) {   //mute
            cmdRet = sendKeyEvent(KeyEvent.KEYCODE_VOLUME_MUTE);
        }
        return cmdRet;
    }

    @Override
    public boolean isMute() {
        AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
        return audioManager.isStreamMute(AudioManager.STREAM_MUSIC);
    }

    @Override
    public int getUsbStorageCnt() {
        StorageManager mStorageManager = mContext.getSystemService(StorageManager.class);
        return mStorageManager.getStorageVolumes().size() - 1;
    }

    @Override
    public boolean setEthMac(String mac) {
        int mode = -1;
        MtkTvFApiSystem mMtkTvFApiSystem = MtkTvFApiSystem.getInstance();
        if (mMtkTvFApiSystem != null) {
            mode = mMtkTvFApiSystem.setEmmcEnvVar("macaddr", mac);
        }
        if (mode > -1) {
            int command = MtkTvFApiSysFactorySvcCmd_e.E_MTK_TV_FAPI_SYS_FACTORY_CMD_SYS_CALL;
            String parameter = "ifconfig eth0 down";
            MtkTvFApiSystem.getInstance().sendCmdToFactorySvc(command, parameter);
            String cmdStr1 = "ifconfig eth0 hw ether " + mac;
            MtkTvFApiSystem.getInstance().sendCmdToFactorySvc(command, cmdStr1);
            String cmdStr2 = "ifconfig eth0 up";
            MtkTvFApiSystem.getInstance().sendCmdToFactorySvc(command, cmdStr2);
        }
        return mode > -1;
    }

    @Override
    public String getEthMac() {
        MtkTvFApiSystem  mMtkTvFApiSystem = MtkTvFApiSystem.getInstance();
        String hardWareAddress = mMtkTvFApiSystem.getEmmcEnvVar("macaddr");
        if (hardWareAddress == null || hardWareAddress.equalsIgnoreCase("")) {
            hardWareAddress = "null";
        }
        return hardWareAddress.toUpperCase();
    }

    @Override
    public String getEthIp() {
        //wifi以及eth都能获取到
        Enumeration<NetworkInterface> interfaces = null;
        try {
            interfaces = NetworkInterface.getNetworkInterfaces();
        } catch (SocketException e) {
            e.printStackTrace();
        }
        String hardWareAddress = null;
        NetworkInterface iF = null;
        Enumeration<InetAddress> mInetAddress = null;
        if (interfaces == null) {
            return null;
        }
        while (interfaces.hasMoreElements()) {
            iF = interfaces.nextElement();
            mInetAddress = iF.getInetAddresses();
            while (mInetAddress.hasMoreElements()) {
                InetAddress inetAddress = (InetAddress) mInetAddress
                        .nextElement();
                if (inetAddress != null && inetAddress instanceof Inet4Address) {
                    if (inetAddress.getHostAddress().equals("127.0.0.1")) {
                        continue;
                    }
                    hardWareAddress = inetAddress.getHostAddress();
                }
            }
            if (hardWareAddress != null) {
                break;
            }
        }
        return hardWareAddress;
    }

    @Override
    public String getWifiMac() {
        WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
        final int macRandomizationMode = Settings.Global.getInt(
                mContext.getContentResolver(), "wifi_connected_mac_randomization_enabled", 0);
        final String macAddress = wifiInfo == null ? "" : wifiInfo.getMacAddress();

        if (TextUtils.isEmpty(macAddress)) {
            Log.e(TAG, "wifi mac Unavailable");
        } else if (macRandomizationMode == 1 && "02:00:00:00:00:00".equals(macAddress)) {
            Log.w(TAG, "MAC is randomized");
        }

        return macAddress.toUpperCase();
    }

    @Override
    public boolean setWifiEnable(boolean isEnable) {
        mWifiManager.setWifiEnabled(isEnable);
        return true;
    }

    @Override
    public boolean isWifiEnable() {
        return mWifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLED
                || mWifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLING;
    }

    @Override
    public List<ScanResult> getWifiScanResult() {
        return mWifiScanResult;
    }

    @Override
    public int wifiScan() {

        if (!isWifiEnable()) {
            setWifiEnable(true);
        }
        mWifiScanResult.clear();
        mWifiManager.startScan();
        ConnectivityManager mConnectivityManager = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
        return mConnectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState().ordinal();
    }

    @Override
    public void unRegisterWifiReceiver() {
        if (true == wifiReceiverFlag) {
            mContext.unregisterReceiver(wifiReceiver);
            wifiReceiverFlag = false;
        }
    }

    @Override
    public String getBtVersion() {
        return "5.0";
    }

    @Override
    public String getBtMac() {
        BluetoothAdapter btAdapt = BluetoothAdapter.getDefaultAdapter();
        String mac = btAdapt.getAddress();
        return mac.toUpperCase();
    }

    @Override
    public boolean startBtDiscovery(String ap) {
        BluetoothAdapter btAdapt = BluetoothAdapter.getDefaultAdapter();
        if (!btAdapt.isDiscovering()) {
            mBtAp = ap;
            mStartBtDiscoveryTime = System.currentTimeMillis();
            mBtDiscoveryDev = null;
            btAdapt.startDiscovery();
            registerBtReceiver();
        }
        return true;
    }

    @Override
    public BluetoothDevice getBtDiscoveryDev() {
        return mBtDiscoveryDev;
    }

    private BroadcastReceiver searchDevices = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            if (System.currentTimeMillis() - mStartBtDiscoveryTime > START_BT_CHECK_MS) {
                Log.e(TAG, "BT check timeout");
                for (ResultListener l : mListeners) {
                    l.onBtDiscoveryResult(mBtDiscoveryDev);
                }
                BluetoothAdapter.getDefaultAdapter().cancelDiscovery();
                unregisterBtReceiver();
                return;
            }

            String action = intent.getAction();
            if (action.equals(BluetoothDevice.ACTION_FOUND)) { //found device
                mBtDiscoveryDev = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                if (!TextUtils.isEmpty(mBtDiscoveryDev.getName())) {
                    Log.d(TAG, "BT: " + mBtDiscoveryDev.getName());
                    if (TextUtils.isEmpty(mBtAp)) {   // mBtAp empty for test
                        for (ResultListener l : mListeners) {
                            l.onBtDiscoveryResult(mBtDiscoveryDev);
                        }
                        // won't cancelDiscovery
                    } else if (mBtDiscoveryDev.getName().contains(mBtAp)) {
                        Log.d(TAG, "BT: device " + mBtDiscoveryDev.getName() + " match ap " + mBtAp);
                        for (ResultListener l : mListeners) {
                            l.onBtDiscoveryResult(mBtDiscoveryDev);
                        }
                        BluetoothAdapter.getDefaultAdapter().cancelDiscovery();
                        unregisterBtReceiver();
                    }
                }
            }
        }
    };

    @Override
    public String[] getBtConnectedDev() {
        BluetoothAdapter mBtAdapter = BluetoothAdapter.getDefaultAdapter();
        Set<BluetoothDevice> bondedDevices = mBtAdapter.getBondedDevices();
        if (bondedDevices.size() == 0) {
            return new String[]{"null"};
        }
        String[] temp = new String[bondedDevices.size()];
        int i = 0;
        for (BluetoothDevice device:bondedDevices) {
            temp[i++] = device.getName();
        }
        return temp;
    }

    @Override
    public String getSerialNumber() {
        if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
            return "";
        } else {
            return Build.getSerial();
        }

    }

    @Override
    public boolean setBalance(Types.Balance balance) {
        switch (balance) {
            case LEFT:
                Settings.Global.putInt(mContext.getContentResolver(), "sound_balance", BALANCE_LEFT);
                break;
            case RIGHT:
                Settings.Global.putInt(mContext.getContentResolver(), "sound_balance", BALANCE_RIGHT);
                break;
            case STEREO:
                Settings.Global.putInt(mContext.getContentResolver(), "sound_balance", BALANCE_STEREO);
                break;
            default:
                break;
        }
        return true;
    }

    @Override
    public int getBalance() {
        int balance = Settings.Global.getInt(mContext.getContentResolver(), "sound_balance", 0);
        if (balance < 0) {
            return Types.Balance.LEFT.ordinal();
        } else if (balance > 0) {
            return Types.Balance.RIGHT.ordinal();
        } else {
            return Types.Balance.STEREO.ordinal();
        }
    }

    @Override
    public boolean sendKeyEvent(int keyCode) {
        try {
            Runtime runtime = Runtime.getRuntime();
            runtime.exec("input keyevent " + keyCode);
        } catch (IOException e) {
            Log.e(TAG, "Exception when send long keyCode");
            return false;
        }
        return true;
    }

    @Override
    public boolean setScreenSaverTime(int minutes) {
        return Settings.System.putInt(
                mContext.getContentResolver(), Settings.System.SCREEN_OFF_TIMEOUT, minutes * SECONDS_IN_ONE_MINUTE  * MS_IN_ONE_SECONDS);  // to ms
    }

    @Override
    public int getScreenSaverTime() {
        int ms = Settings.System.getInt(mContext.getContentResolver(), Settings.System.SCREEN_OFF_TIMEOUT, Types.INVALID);
        if (ms == Types.INVALID) {
            Log.e(TAG, "unknow screen save time ms = " + ms);
            return Types.INVALID;
        } else {
            return ms / MS_IN_ONE_SECONDS / SECONDS_IN_ONE_MINUTE;  // to minutes
        }
    }

    @Override
    public boolean setNoOperSleepTime(int minutes) {
        int ms = (minutes == -1) ? -1 : minutes * SECONDS_IN_ONE_MINUTE * MS_IN_ONE_SECONDS;  // to ms
        return Settings.Secure.putInt(mContext.getContentResolver(), SETTINGS_SECURE_SLEEP_TIMEOUT, ms);
    }

    @Override
    public int getNoOperSleepTime() {
        int ms = Settings.Secure.getInt(mContext.getContentResolver(), SETTINGS_SECURE_SLEEP_TIMEOUT, Types.INVALID);
        if (ms == Types.INVALID) {
            Log.e(TAG, "unknow no operation time ms = " + ms);
            return Types.INVALID;
        } else {
            return ms / MS_IN_ONE_SECONDS / SECONDS_IN_ONE_MINUTE;  // to minutes
        }
    }

    @Override
    public boolean setNoSignalPowerOffTime(int minutes) {
        int mode = toMtkNoSignalPowerOffMode(minutes);
        if (mode == Types.INVALID) {
            Log.e(TAG, "unsupport no signal power off time minutes = " + minutes);
            return false;
        } else {
            return Settings.Global.putInt(mContext.getContentResolver(), "no_signal_auto_power_off", mode);
        }
    }

    @Override
    public int getNoSignalPowerOffTime() {
        int mode = Settings.Global.getInt(mContext.getContentResolver(), "no_signal_auto_power_off", Types.INVALID);
        return fromMtkNoSignalPowerOffMode(mode);
    }

    @Override
    public String getProjectID() {
        return MtkTvFApiInformation.getInstance().getIniParameter(PATH_PROJECT_INI, FACTORY_PROJECT_ID);
    }

    @Override
    public String getPQVersion() {
        String pqString = "0.0";
        MtkTvFApiDisplay mMtkTvFApiDisplay = MtkTvFApiDisplay.getInstance();

        if (mMtkTvFApiDisplay != null) {
            pqString = mMtkTvFApiDisplay.getPQVersion(0);
        }

        return pqString;
    }

    @Override
    public String getAQVersion() {
        String aqString = "0.0";
        MtkTvFApiInformation mMtkTvFApiInformation = MtkTvFApiInformation.getInstance();
        if (mMtkTvFApiInformation != null) {
            aqString =
                    mMtkTvFApiInformation.getIniParameter(FACTORY_PAGE1_AQ_VERSION_PATH, FACTORY_INI_PANEL_VER);
        }

        return aqString;
    }

    @Override
    public String getPanelVersion() {
        String panelVersion = "0.0";

        MtkTvFApiInformation mMtkTvFApiInformation = MtkTvFApiInformation.getInstance();
        if (null != mMtkTvFApiInformation) {
            String mPanelPath = mMtkTvFApiInformation.getIniParameter(FACTORY_PAGE2_CUSTOMER_PATH,
                                FACTORY_INI_PANEL_PATH);
            Log.d(TAG, "panel path : " + mPanelPath);
            panelVersion = mMtkTvFApiInformation.getIniParameter(mPanelPath,
                          FACTORY_INI_PANEL_VER);
        }

        return panelVersion;
    }

    @Override
    public String getDataVersion() {
        String dataVersion = "0.0";

        MtkTvFApiInformation mMtkTvFApiInformation = MtkTvFApiInformation.getInstance();
        if (null != mMtkTvFApiInformation) {
            dataVersion = mMtkTvFApiInformation.getIniParameter(FACTORY_PAGE2_CUSTOMER_PATH,
                                            FACTORY_INI_PANEL_VER);
        }

        return dataVersion;
    }

    @Override
    public String getBuildTime() {
        String buildTime = SystemProperties.get(PROPERTIE_BUILDTIME, "");

        return buildTime;
    }

    @Override
    public String getPanelName() {
        String panelName = null;
        String fullName = null;

        MtkTvFApiDisplay mMtkTvFApiDisplay = MtkTvFApiDisplay.getInstance();
        if (mMtkTvFApiDisplay != null) {
            fullName = mMtkTvFApiDisplay.getPanelIni();
            if (!TextUtils.isEmpty(fullName)) {
                panelName = fullName.substring(fullName.lastIndexOf("/") + 1,
                        fullName.lastIndexOf("."));
            }
        }

        return panelName;
    }

    @Override
    public boolean getHDCPKey10() {
        boolean ret = false;

        MtkTvFApiSystem mMtkTvFApiSystem = MtkTvFApiSystem.getInstance();
        if (null != mMtkTvFApiSystem) {
            ret = mMtkTvFApiSystem.checkSystemKey(
                    MtkTvFApiKeyManager.EnumSystemKeyType.E_MTK_FAPI_SYSTEM_KEY_HDCP14);
        }

        return ret;
    }

    @Override
    public boolean getHDCPKey2() {
        boolean ret = false;

        MtkTvFApiSystem mMtkTvFApiSystem = MtkTvFApiSystem.getInstance();
        if (null != mMtkTvFApiSystem) {
            ret = mMtkTvFApiSystem.isFileExist(KEY_PATH_HDCP2);
        }

        return ret;
    }

    @Override
    public boolean getWideVineKey() {
        boolean ret = false;

        MtkTvFApiSystem mMtkTvFApiSystem = MtkTvFApiSystem.getInstance();
        if (null != mMtkTvFApiSystem) {
            ret = mMtkTvFApiSystem.checkSystemKey(
                    MtkTvFApiKeyManager.EnumSystemKeyType.E_MTK_FAPI_SYSTEM_KEY_WVCENC);
        }

        return ret;
    }

    @Override
    public boolean getKeystatusPlayready() {
        boolean ret = false;

        MtkTvFApiSystem mMtkTvFApiSystem = MtkTvFApiSystem.getInstance();
        if (null != mMtkTvFApiSystem) {
            ret = mMtkTvFApiSystem.checkSystemKey(
                    MtkTvFApiKeyManager.EnumSystemKeyType.E_MTK_FAPI_SYSTEM_KEY_PLAYREADY30);
        }

        return ret;
    }

    @Override
    public boolean getKeystatusPlayready25() {
        boolean ret = false;

        MtkTvFApiSystem mMtkTvFApiSystem = MtkTvFApiSystem.getInstance();
        if (null != mMtkTvFApiSystem) {
            ret = mMtkTvFApiSystem.checkSystemKey(
                    MtkTvFApiKeyManager.EnumSystemKeyType.E_MTK_FAPI_SYSTEM_KEY_PLAYREADY25);
        }

        return ret;
    }

    @Override
    public boolean getKeymaster() {
        boolean ret = false;

        MtkTvFApiSystem mMtkTvFApiSystem = MtkTvFApiSystem.getInstance();
        if (null != mMtkTvFApiSystem) {
            ret = mMtkTvFApiSystem.checkSystemKey(
                    MtkTvFApiKeyManager.EnumSystemKeyType.E_MTK_FAPI_SYSTEM_KEY_KEYMASTER);
        }

        return ret;
    }


    @Override
    public boolean registerResultListener(ResultListener listener) {
        return mListeners.contains(listener) ? false : mListeners.add(listener);
    }

    @Override
    public boolean unregisterResultListener(ResultListener listener) {
        return mListeners.contains(listener) ? mListeners.remove(listener) : false;
    }


	@Override
	public boolean setWBConnet(){
		//Intent intent = new Intent();
		//Intent intent = new Intent(mContext,com.homwee.factory.FactoryStateService.class);
		//intent.setComponent(new ComponentName("com.homwee.factory.FactoryStateService", "com.homwee.factory.FactoryStateService.mBroadcastReceiver"));

	//	intent.setAction("com.homwee.stateservice.setkey");
	//	intent.putExtra("text", "W/B");
	//	intent.putExtra("color",android.graphics.Color.GREEN);
	//	intent.addFlags(0x01000000);
	//	mContext.sendBroadcast(intent);
	    sendKeyEvent(KeyEvent.KEYCODE_AT);
	    sendKeyEvent(KeyEvent.KEYCODE_NAVIGATE_NEXT);
		return true;
	}

	@Override
	public boolean setConnet(){
		return true;
	}

    /**
     * function.
     */
    private static  List<MtkTvChannelInfoBase> getChannelList() {
        int antenna = MtkTvConfig.getInstance().getConfigValue(MtkTvConfigType.CFG_BS_SVL_ID);
        MtkTvChannelList mtcl = MtkTvChannelList.getInstance();
        int num = mtcl.getChannelCountByFilter(antenna, MtkTvChCommonBase.SB_VNET_ALL);
        Log.d(TAG, "antenna = " + antenna + ", num = " + num);
        return mtcl.getChannelListByFilter(antenna, MtkTvChCommonBase.SB_VNET_ALL, 0, 0, num);
    }

    private static  MtkTvChannelInfoBase findChannel(Types.ChannelType type, int num, List<MtkTvChannelInfoBase> channels) {
        int antenna = MtkTvConfig.getInstance().getConfigValue(MtkTvConfigType.CFG_BS_SVL_ID);
        int medium = toMtkMedium(antenna, type);
        for (MtkTvChannelInfoBase c : channels) {
            if (c.getBrdcstMedium() == medium && c.getChannelNumber() == num) {
                return c;
            }
        }

        return null;
    }

    private void startInspectionActivity(Context context, String value) {
        final Intent intentInpsectionActivity = new Intent(context, SerialPortInspectionActivity.class);
        Bundle bundle = new Bundle();
        bundle.putString("param", value);
        intentInpsectionActivity.putExtras(bundle);
        intentInpsectionActivity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intentInpsectionActivity);
    }

    private void registerBtReceiver() {
        IntentFilter intent = new IntentFilter();
        intent.addAction(BluetoothDevice.ACTION_FOUND);
        intent.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
        intent.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        mContext.registerReceiver(searchDevices, intent);
        btReceiverFlag = true;
    }

    private void unregisterBtReceiver() {
        if (true == btReceiverFlag) {
            mContext.unregisterReceiver(searchDevices);
            btReceiverFlag = false;
        }
    }

    /**
     * data convert.
     *
     */
    private enum MtkSourceId {
        TV, COMPOSITE, COMPONENT, VGA, HDMI_1, HDMI_2, HDMI_3, HDMI_4
    }

    private static int toMtkSourceId(Types.InputSource source) {
        int id = Types.INVALID;

        switch (source) {
            case ATV:
            case DTV:
                id = MtkSourceId.TV.ordinal();
                break;

            case CVBS:
                id = MtkSourceId.COMPOSITE.ordinal();
                break;

            case HDMI:
            case HDMI2:
            case HDMI3:
            case HDMI4:
                id = MtkSourceId.HDMI_1.ordinal() + (source.ordinal() - Types.InputSource.HDMI.ordinal());
                break;

            default:
                Log.e(TAG, "unsupport source = " + source);
        }

        return id;
    }

    private static int fromMtkSourceId(MtkSourceId id) {
        int source = Types.INVALID;

        switch (id) {
            case TV:
                source = Types.InputSource.DTV.ordinal();
                break;

            case COMPOSITE:
                source = Types.InputSource.CVBS.ordinal();
                break;

            case HDMI_1:
            case HDMI_2:
            case HDMI_3:
            case HDMI_4:
                source = Types.InputSource.HDMI.ordinal() + (id.ordinal() - MtkSourceId.HDMI_1.ordinal());
                break;

            default:
                Log.e(TAG, "unsupport mtk source id = " + id);
        }

        return source;
    }

    private static int toMtkSourceType(Types.InputSource source) {
        int type = Types.INVALID;

        switch (source) {
            case ATV:
                type = MtkTvFApiDisplayTypes.EnumInputSourceType.E_ATV.ordinal();
                break;

            case DTV:
                type = MtkTvFApiDisplayTypes.EnumInputSourceType.E_DTV.ordinal();
                break;

            case CVBS:
                type = MtkTvFApiDisplayTypes.EnumInputSourceType.E_CVBS.ordinal();
                break;

            case HDMI:
            case HDMI2:
            case HDMI3:
            case HDMI4:
                type = MtkTvFApiDisplayTypes.EnumInputSourceType.E_HDMI.ordinal();
                break;

            default:
                Log.e(TAG, "unsupport source = " + source);
        }

        return type;
    }

    private static int fromMtkSourceType(MtkTvFApiDisplayTypes.EnumInputSourceType type) {
        int source = Types.INVALID;

        switch (type) {
            case E_ATV:
                source = Types.InputSource.ATV.ordinal();
                break;

            case E_DTV:
                source = Types.InputSource.DTV.ordinal();
                break;

            case E_CVBS:
                source = Types.InputSource.CVBS.ordinal();
                break;

            case E_HDMI:
                source = Types.InputSource.HDMI.ordinal();
                break;

            default:
                Log.e(TAG, "unsupport mtk source type = " + type);
        }

        return source;
    }

    private static int toMtkMedium(int antenna, Types.ChannelType type) {
        int medium = Types.INVALID;

        if (antenna == MTK_ANTENNA_AIR) {
            if (type == Types.ChannelType.ATV) {
                medium = MtkTvChCommonBase.BRDCST_MEDIUM_ANA_TERRESTRIAL;
            } else {
                medium = MtkTvChCommonBase.BRDCST_MEDIUM_DIG_TERRESTRIAL;
            }
        } else if (antenna == MTK_ANTENNA_CABLE) {
            if (type == Types.ChannelType.ATV) {
                medium = MtkTvChCommonBase.BRDCST_MEDIUM_ANA_CABLE;
            } else {
                medium = MtkTvChCommonBase.BRDCST_MEDIUM_DIG_CABLE;
            }
        } else if (antenna == MTK_ANTENNA_SATELLITE) {
            if (type == Types.ChannelType.ATV) {
                medium = MtkTvChCommonBase.BRDCST_MEDIUM_ANA_SATELLITE;
            } else {
                medium = MtkTvChCommonBase.BRDCST_MEDIUM_DIG_SATELLITE;
            }
        } else {
            Log.e(TAG, "unsupport antenna = " + antenna);
        }

        return medium;
    }

    private static int toChannelType(int mtkMedium) {
        int type = Types.INVALID;
        switch (mtkMedium) {
            case MtkTvChCommonBase.BRDCST_MEDIUM_ANA_TERRESTRIAL:
            case MtkTvChCommonBase.BRDCST_MEDIUM_ANA_CABLE:
            case MtkTvChCommonBase.BRDCST_MEDIUM_ANA_SATELLITE:
                type = Types.ChannelType.ATV.ordinal();
                break;

            case MtkTvChCommonBase.BRDCST_MEDIUM_DIG_TERRESTRIAL:
            case MtkTvChCommonBase.BRDCST_MEDIUM_DIG_CABLE:
            case MtkTvChCommonBase.BRDCST_MEDIUM_DIG_SATELLITE:
                type = Types.ChannelType.DTV.ordinal();
                break;

            default:
                Log.e(TAG, "unsupport mtk medium = " + mtkMedium);
        }

        return type;
    }

    private int toMtkFactoryCtMode(Types.ColorTempMode mode) {
        for (int i = 0; i < mFactoryCtModeMap.length; i++) {
            if (mode == mFactoryCtModeMap[i]) {
                return i;
            }
        }

        Log.e(TAG, "unsupport CT mode = " + mode);
        return Types.INVALID;
    }

    private Types.ColorTempMode fromMtkFactoryCtMode(MtkTvFApiDisplayTypes.EnumColorTemperature mode) {
        return mFactoryCtModeMap[mode.ordinal()];
    }

    private enum MtkNoSignalPowerOffMode {
        OFF, MIN_5, MIN_10, MIN_15, MIN_30, MIN_60
    }

    private int toMtkNoSignalPowerOffMode(int minutes) {
        for (int i = 0; i < mNoSignalPowerOffTimeMap.length; i++) {
            if (mNoSignalPowerOffTimeMap[i] == minutes) {
                return i;
            }
        }

        Log.e(TAG, "unsupport no signal power off minutes = " + minutes);
        return Types.INVALID;
    }

    private int fromMtkNoSignalPowerOffMode(int mode) {
        if (mode < 0 || mode >= MtkNoSignalPowerOffMode.values().length) {
            Log.e(TAG, "unkown no signal power off mode = " + mode);
            return Types.INVALID;
        } else {
            return mNoSignalPowerOffTimeMap[mode];
        }
    }

    private Types.FactoryColorTempData fromMtkCtData(MtkTvFApiDisplayTypes.ColorTempData ctData) {
        Types.FactoryColorTempData fctData = new Types.FactoryColorTempData();
        fctData.rGain = ctData.redGain;
        fctData.gGain = ctData.greenGain;
        fctData.bGain = ctData.blueGain;
        fctData.rOffset = ctData.redOffset;
        fctData.gOffset = ctData.greenOffset;
        fctData.bOffset = ctData.blueOffset;

        return fctData;
    }

    private static MtkTvFApiDisplayTypes.ColorTempData toMtkCtData(Types.FactoryColorTempData fctData) {
        return new MtkTvFApiDisplayTypes.ColorTempData(
                fctData.rGain, fctData.gGain, fctData.bGain, fctData.rOffset, fctData.gOffset, fctData.bOffset);
    }
    @Override
	public int getCECStatus(){
        int cecStatus = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.HDMI_CONTROL_ENABLED, 1);
		return cecStatus;
	}

	@Override
    public int setCECStatus(int cecStatus){
		int ret = 0;
		if(cecStatus == 1){
            Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.HDMI_CONTROL_ENABLED, 1);
            ret = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.HDMI_CONTROL_ENABLED, 1) == 1 ? 1 :0;
		} else if(cecStatus == 2){
            Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.HDMI_CONTROL_ENABLED, 0);
            ret = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.HDMI_CONTROL_ENABLED, 1) == 0 ? 1 :0;
		}
		return ret;
	}

	@Override
	public int presetChannel(int type){
		int ret = 0;
		broadcastIntentOut(
				"mtk.intent.event.preset.channel.start");
        if(type == 0){
            ret = MtkTvConfig.getInstance().loadChannelListByPath(1, "/vendor/tvconfig/apollo/channel_list");
		} else {
			ret = MtkTvConfig.getInstance().loadChannelList(1);
		}
		broadcastIntentOut(
				"mtk.intent.event.preset.channel.end");
		if(ret == 0){
			MtkTvChannelInfoBase channelinfo = new MtkTvChannelInfoBase(0xffff, 0);
			channelinfo.setChannelId(0xffffffff);
			MtkTvBroadcast.getInstance().channelSelect(channelinfo, false);
		}

		return ret;


	}

	private void broadcastIntentOut(String broadcastType) {

		try {

			synchronized (Antv.class) {

				Intent intent = new Intent();

				intent.setAction(broadcastType);
				mContext.sendBroadcastAsUser(intent,
						UserHandle.getUserHandleForUid(1000));
				Log.d(TAG, "broadcastIntentOut==>do broadcast broadcastType="
						+ broadcastType);
			}
		} catch (Exception e) {

			Log.d(TAG, "RemoteException:" + e.getMessage());
		}
	}
}
